﻿package net.wangit.framework.config;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.wangit.Path;
import net.wangit.framework.exception.ConfigurationException;
import net.wangit.jdbc.database.Database;
import net.wangit.jdbc.generator.Generator;
import net.wangit.jdbc.transaction.TransactionImplementor;
import net.wangit.support.PageNavigator;
import net.wangit.support.Validator;
import net.wangit.util.ClassUtil;
import net.wangit.util.XMLUtil;
import net.wangit.view.Suite;
import net.wangit.view.element.ElementComponent;
import net.wangit.view.unit.UnitComponent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;

/**
 * Bean工厂
 * 
 * @author watson
 * Feb 22, 2010
 */
public class BeanFactory {

	private static final Log log = LogFactory
			.getLog(net.wangit.framework.config.BeanFactory.class);
	private static final String DATABASE_NAME = "database";
	private static final String TRANSACTION_NAME = "transaction";
	public static final String UNIT_NAME = "unit";
	public static final String ELEMENT_NAME = "element";
	public static final String VALIDATOR_NAME = "validator";
	public static final String SUITE_NAME = "suite";
	public static final String GENERATOR_NAME = "generator";
	public static final String NAVIGATOR_NAME = "navigator";
	public static final String BEAN = "bean";
	public static final String ID = "id";
	private static final String CLASS = "class";
	private static Map<String, String> databases;
	private static Map<String, String> transactions;
	private static Map<String, String> units;
	private static Map<String, String> elements;
	private static Map<String, String> suites;
	private static Map<String, Validator> validators;
	private static Map<String, Generator> generators;
	private static Map<String, PageNavigator> navigators;


	public BeanFactory() {
	}

	public static String getPath() {
		return (new StringBuilder(String.valueOf(Path.getHomePath()))).append(
				"/components.xml").toString();
	}

	public static void load() {
		databases = new HashMap<String, String>();
		transactions = new HashMap<String, String>();
		units = new HashMap<String, String>();
		elements = new HashMap<String, String>();
		suites = new HashMap<String, String>();
		validators = new HashMap<String, Validator>();
		generators = new HashMap<String, Generator>();
		navigators = new HashMap<String, PageNavigator>();
		String path = getPath();
		try {
			Document document = XMLUtil.parseByPath(path);
			Element root = document.getRootElement();
			load(root, databases, BeanFactory.DATABASE_NAME);
			load(root, transactions, BeanFactory.TRANSACTION_NAME);
			load(root, units, BeanFactory.UNIT_NAME);
			load(root, elements, BeanFactory.ELEMENT_NAME);
			load(root, suites, BeanFactory.SUITE_NAME);
			List list = root.element(BeanFactory.VALIDATOR_NAME).elements(
					BeanFactory.BEAN);
			for (int i = 0; i < list.size(); i++) {
				Element element = (Element) list.get(i);
				String id = element.attributeValue(BeanFactory.ID);
				String className = element.attributeValue(BeanFactory.CLASS);
				validators.put(id, createValidator(className));
			}

			list = root.element(BeanFactory.GENERATOR_NAME).elements(
					BeanFactory.BEAN);
			for (int i = 0; i < list.size(); i++) {
				Element element = (Element) list.get(i);
				String id = element.attributeValue(BeanFactory.ID);
				String className = element.attributeValue(BeanFactory.CLASS);
				generators.put(id, createGenerator(className));
			}

			list = root.element(BeanFactory.NAVIGATOR_NAME).elements(
					BeanFactory.BEAN);
			for (int i = 0; i < list.size(); i++) {
				Element element = (Element) list.get(i);
				String id = element.attributeValue(BeanFactory.ID);
				String className = element.attributeValue(BeanFactory.CLASS);
				navigators.put(id, createNavigator(className));
			}

		} catch (Exception e) {
			log.error((new StringBuilder("could not load beans: "))
					.append(path).toString(), e);
			throw new ConfigurationException((new StringBuilder(
					"could not load beans: ")).append(path).toString(), e);
		}
	}

	public static UnitComponent getUnitComponent(String id) throws Exception {
		String className = units.get(id);
		try {
			return (UnitComponent) ClassUtil.loadClass(className).newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("unsupported unit component : "))
					.append(id).append("(").append(className).append(")")
					.toString());
			throw e;
		}
	}

	public static ElementComponent getElementComponent(String id)
			throws Exception {
		String className = elements.get(id);
		try {
			return (ElementComponent) ClassUtil.loadClass(className)
					.newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("unsupported element component : "))
					.append(id).append("(").append(className).append(")")
					.toString());
			throw e;
		}
	}

	public static Database getDatabase(String id) throws Exception {
		String className = databases.get(id.toLowerCase());
		try {
			Database database;
			database = (Database) ClassUtil.loadClass(className).newInstance();
			database.setName(id);
			return database;
		} catch (Exception e) {
			log.error((new StringBuilder("unsupported Database : ")).append(id)
					.append("(").append(className).append(")").toString());
			throw e;
		}
	}

	public static TransactionImplementor getTransaction(String id)
			throws Exception {
		String className = transactions.get(id.toLowerCase());
		try {
			TransactionImplementor transaction = (TransactionImplementor) ClassUtil
					.loadClass(className).newInstance();
			return transaction;
		} catch (Exception e) {
			log.error((new StringBuilder("unsupported Transaction : ")).append(
					id).append("(").append(className).append(")").toString());
			throw e;
		}
	}

	public static Validator getValidator(String id) {
		return validators.get(id);
	}

	public static Generator getGenerator(String id) {
		return generators.get(id);
	}

	public static PageNavigator getNavigator(String id) {
		return navigators.get(id);
	}

	public static Suite getSuite(String id) {
		String className = suites.get(id);
		try {
			return (Suite) ClassUtil.loadClass(className).newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("could not load Suite: ")).append(
					className).toString(), e);
			throw new ConfigurationException((new StringBuilder(
					"could not load Suite: ")).append(className).toString(), e);
		}
	}

	private static Validator createValidator(String className) throws Exception {
		try {
			return (Validator) ClassUtil.loadClass(className).newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("could not load Validator: ")).append(
					className).toString(), e);
			throw new ConfigurationException(
					(new StringBuilder("could not load Validator: ")).append(
							className).toString(), e);
		}
	}

	private static Generator createGenerator(String className) throws Exception {
		try {
			return (Generator) ClassUtil.loadClass(className).newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("could not load Generator: ")).append(
					className).toString(), e);
			throw new ConfigurationException(
					(new StringBuilder("could not load Generator: ")).append(
							className).toString(), e);
		}
	}

	private static PageNavigator createNavigator(String className)
			throws Exception {
		try {
			return (PageNavigator) ClassUtil.loadClass(className).newInstance();
		} catch (Exception e) {
			log.error((new StringBuilder("could not load PageNavigator: "))
					.append(className).toString(), e);
			throw new ConfigurationException((new StringBuilder(
					"could not load PageNavigator: ")).append(className)
					.toString(), e);
		}
	}

	private static void load(Element root, Map<String, String> map, String nodeName)
			throws Exception {
		List<?> list = root.element(nodeName).elements(BeanFactory.BEAN);
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			String id = element.attributeValue(BeanFactory.ID);
			String className = element.attributeValue(BeanFactory.CLASS);
			map.put(id, className);
		}

	}

}
